home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 3
/
Cream of the Crop 3.iso
/
comm
/
wnos5src.zip
/
DOMSERV.C
< prev
next >
Wrap
Text File
|
1993-10-14
|
19KB
|
794 lines
/* Domain/Name server
* Copyright 1991/2 KA9Q, PA0GRI, DK5DC and DB3FL
*
* ported to WNOS from a previous PA0GRI issue by DB3FL
*
* some code streaming and fixing done - DB3FL.91xxxx/92xxxx
* added cache from DK5DC - DB3FL.92xxxx
* fixes by WZ8Y - 9206xx
*
*/
#include "global.h"
#include "config.h"
#include "socket.h"
#include "domain.h"
#include "files.h"
#include "netuser.h"
#include "iface.h"
#define RR_QUERY 8
#define RR_INQUERY 9
Cache *cache;
static int near
strxlen(char *s)
{
int i = 0;
while(*s++ != '\0') {
i++;
}
return i;
}
/* Resolve an arbitrary record */
static struct rr * near
resolverec(char *name,int type)
{
struct rr *rrp;
char *pname = NULLCHAR, *cname = NULLCHAR;
FILE *dbase;
struct rr_memory *memory;
if(name == NULLCHAR) {
return NULLRR;
}
if(DBloaded) {
dbase = NULLFILE;
} else {
if((dbase = Fopen(Dfile,READ_TEXT,0,0)) == NULLFILE) {
return NULLRR;
}
}
memory = mxallocw(sizeof(struct rr_memory));
memory->Dname[0] = '\0'; /* initialize global area */
memory->Dttl = 3600;
memory->Dclass = 1;
/* This code can handle a few weird cases. It works when there's
* a PTR to a CNAME to the sought record, as well as when there's a
* CNAME to a PTR to the record. But it allows only one of each kind
* of indirection to prevent infinite loops.
*/
while((rrp = dfind(dbase,name,type,memory)) == NULLRR){
/* No matching record was found, let's see if it's an alias */
if(cname == NULLCHAR
&& (rrp = dfind(dbase,name,TYPE_CNAME,memory)) != NULLRR){
if((cname = strxdup(rrp->rdata.name)) == NULLCHAR) {
break;
}
name = cname;
rewind(dbase);
memory->Dname[0] = '\0'; /* initialize global area */
memory->Dttl = 3600;
memory->Dclass = 1;
memory->rrp = NULLRR;
xfree(memory->dorigin);
memory->dorigin = NULLCHAR;
free_rr(rrp);
continue; /* Try again */
}
/* Lacking that, try a pointer entry... */
if(pname == NULLCHAR
&& (rrp = dfind(dbase,name,TYPE_PTR,memory)) != NULLRR){
if((pname = strxdup(rrp->rdata.name)) == NULLCHAR) {
break;
}
name = pname;
rewind(dbase);
memory->Dname[0] = '\0'; /* initialize global area */
memory->Dttl = 3600;
memory->Dclass = 1;
memory->rrp = NULLRR;
xfree(memory->dorigin);
memory->dorigin = NULLCHAR;
free_rr(rrp);
continue;
}
/* Nope, nothing. Give up */
break;
}
Fclose(dbase);
xfree(pname);
xfree(cname);
xfree(memory->dorigin);
xfree(memory);
return rrp;
}
#ifdef XXX
/* Try to figure out if we are an authority; current strategy is:
* if a domain server is defined we do not have athority
*/
static int near
haveaa(char *name)
{
return Dhaveaa;
struct rr *rrp;
int len, cnt = 0;
char *cp = name;
/* Try to find a SOA for the whole address and by stripping off
the first part of the address. */
while(cnt < 4 && (rrp = resolverec(cp,TYPE_SOA)) == NULLRR){
if((cp = strchr(cp,'.')) == NULLCHAR)
break;
if(*(++cp) == '\0')
break;
++cnt;
}
if(rrp != NULLRR){
len = strxlen(rrp->rdata.soa->mname);
if(rrp->rdata.soa->mname[len-1] == '.')
--len;
if(len == strxlen(Hostname) &&
strncmp(Hostname,rrp->rdata.soa->mname,len) == 0){
free_rr(rrp);
return 1;
}
free_rr(rrp);
}
return 0;
}
#endif
/* Main entry point for domain name -> arbitrary record resolution.
* Returns a null pointer if name is definitely not valid.
*/
static struct rr * near
rresolve(char *name,int type,int16 fflag)
{
char *buf;
int i, len, recurse = 0, auth = 0, lcount = 0;
int16 flags;
struct rr *rrp = NULLRR, *rr, *rrtmp;
struct dhdr *dhdr;
struct mbuf *bp;
struct dserver *dp = Dlist;
while((rrp = resolverec(name,type)) == NULLRR){
if(dp == NULLDOM) {
break;
}
if(auth == 0) {
if(Dhaveaa) {
#ifdef XXX
if(haveaa(name)) { /* Quit if we are an authority */
#endif
return NULLRR;
} else {
auth = -1;
}
}
if(uploadstatus) {
break;
}
/* Not in file, send query */
flags = DOM_DORECURSE | fflag; /* Recursion desired */
dhdr = bld_dhdr(QUERY,QUERY,flags,NO_ERROR,name,CLASS_IN,type);
buf = mxallocw(512); /* buf is freed by sendquery */
len = res_mkbuf(dhdr,buf,512);
free_dhdr(dhdr); /* actualy we need to keep the question for
later reference when an answer comes in */
dp->queries++;
if(sendquery(dp->address,buf,len,&bp,dp->timeout) > 0) {
dhdr = mxallocw(sizeof(struct dhdr));
ntohdomain(dhdr,&bp);
dp->responses++;
proc_answer(dhdr,dp,NULLFILE);
if(dhdr->rcode != NO_ERROR) {
break;
} else {
for(i = 0; i < dhdr->ancount; i++){
rrp = copy_rr(dhdr->ans[i]);
if(strnicmp(rrp->name,name,strxlen(name)) != 0) {
continue;
}
/* Got one */
switch(rrp->type) {
case TYPE_CNAME:
/* Change the query name to the
* cname and go back again
*/
if(++recurse == MAXCNAME) {
/* too many recursions */
break;
}
xfree(name);
name = strxdup(rrp->rdata.name);
/* rescan the responces */
i = -1;
continue;
}
break;
}
}
free_dhdr(dhdr);
break;
}
if(errno == EABORT) {
return NULLRR;
}
/* Timeout; back off this one and try another server */
dp->timeout += 5000;
dp->missers++;
if((dp = dp->next) == NULLDOM) {
break;
}
if(++lcount > Dretries) {
return NULLRR;
}
}
rr = rrp; /* Remove any NULL records */
while(rr != NULLRR && rr->rdlength == 0){
rrp = rr->next;
rr->next = NULLRR;
free_rr(rr);
rr = rrp;
}
while(rr != NULLRR && rr->next != NULLRR){
if(rr->next->rdlength == 0) {
rrtmp = rr->next->next;
rr->next->next = NULLRR;
free_rr(rr->next);
rr->next = rrtmp;
} else {
rr = rr->next;
}
}
return rrp;
}
/*----------------------------------------------------------------------*
*retrieve the next useable entry in cache *
*-----------------------------------------------------------------------*/
static Cache * near
getentry(void)
{
Cache *ocap, *cap = cache;
int i;
time_t ti;
/*-------------------------------------------------------------------*
* scan cache for an useable entry. This might be a free entry.. *
* cap->ti == 0 or the oldest entry in Cache *
*--------------------------------------------------------------------*/
time(&ti);
for (i = 0; i < Dcache_size; i++) {
if (cap->ti == 0) {
return(cap);
}
if (ti >= cap->ti) {
ti = cap->ti;
ocap = cap;
}
cap++;
}
return(ocap);
}
/*----------------------------------------------------------------------*
* put an entry into the cache for later access *
*-----------------------------------------------------------------------*/
static Cache * near
putcache(char *name,char *host,int32 addr,Rtype type,Ctype ctype)
{
/*-------------------------------------------------------------------*
* Found it, put in cache *
*--------------------------------------------------------------------*/
Cache *cap = getentry();
semwait(&Cwrite,1); /* -serialize Cache access */
/*-------------------------------------------------------------------*
* make correct entries for valid and invalid entries *
*--------------------------------------------------------------------*/
if (type == Address && ctype == Found) { /* via resolve_a()*/
sprintf(cap->name,"%.39s",strtok(name,"\t "));
} else if (ctype == Found) { /* found in file */
sprintf(cap->name,"%.39s",host);
}
if (type == Name && ctype == Missing) {
cap->address = 0;
sprintf(cap->name,"%.39s",host);
} else {
cap->address = (ctype != Found) ? 0 : addr;
}
cap->type = ctype;
cap->ti = time(NULL);
semrel(&Cwrite);
return cap;
}
/*----------------------------------------------------------------------*
* Perform a cache search.
*-----------------------------------------------------------------------*/
static Cache * near
cache_search(char *name,Rtype type)
{
int i;
char *cp;
Cache *cap = cache;
for (i = 0; i < Dcache_size; i++) {
if(i == Dcache_size) {
break;
}
if(cap->ti == 0) {
continue;
}
if(type == Name) {
if(cap->name[0] != '\0') {
if(strchr(name,'.') == NULLCHAR) {
if((cp = strchr(cap->name,'.')) != NULLCHAR) {
*cp = '\0';
}
if(stricmp(cap->name,name) == 0) {
*cp = '.';
return cap;
}
*cp = '.';
} else if(strnicmp(cap->name,name,(strxlen(name) - 1)) == 0) {
return cap;
}
}
} else {
if(cap->address != 0 && cap->address == aton(name)) {
return cap;
}
}
cap++;
}
return(0);
}
/* Main entry point for domain name -> address resolution.
* Returns 0 if name is definitely not valid.
*/
int32
resolve(char *name)
{
char *sname;
int state = Found;
int32 addr = 0;
struct rr *arrp = NULLRR;
Cache *cap;
if(*name == '[') {
return aton(name + 1);
}
if(isaddr(name)) {
return aton(name);
}
if((cap = cache_search(name,Name)) != 0) {
return (cap->type == Found) ? cap->address : 0;
}
sname = strxdup(name);
if((arrp = rresolve(sname,TYPE_A,DOM_CANRECURSE)) != NULLRR) {
if(arrp->rdlength == 4) {
addr = arrp->rdata.addr;
xfree(sname);
sname = strxdup(arrp->name);
}
}
if(addr == 0) {
state = Missing;
}
if(cap == 0) {
putcache(NULLCHAR,sname,addr,Name,state);
}
xfree(sname);
free_rr(arrp);
return addr;
}
/* entry point for address -> domain name resolution.
* Returns NULLCHAR if address is not found.
*/
char *
resolve_a(int32 ip_address,int shorten)
{
static char pname[80];
Cache *cap;
if(ip_address == 0) {
return NULLCHAR;
}
sprintf(pname,"%u.%u.%u.%u",
hibyte(hiword(ip_address)),lobyte(hiword(ip_address)),
hibyte(loword(ip_address)),lobyte(loword(ip_address)));
if((cap = cache_search(pname,Address)) != 0 && cap->type == Found) {
if(cap->name[strxlen(cap->name) - 1] != '.') {
if(shorten) {
return cap->name;
} else if (Dsuffix) {
sprintf(pname,"%s.%s",cap->name,Dsuffix);
return pname;
}
} else {
if(!shorten) {
return cap->name;
}
if(Dsuffix) {
char *j;
strcpy(pname,cap->name);
j = strstr(pname,Dsuffix);
if (j > pname && *(--j) == '.') {
*j = '\0';
} else {
pname[strxlen(pname)-1] = '\0';
}
return pname;
}
}
}
return NULLCHAR;
#ifdef notdef
struct rr *rrp, *irrp, *prrp;
sprintf( pname, "%u.%u.%u.%u%s",
lobyte(loword(ip_address)),
hibyte(loword(ip_address)),
lobyte(hiword(ip_address)),
hibyte(hiword(ip_address)),
shorten ? "" : ".IN-ADDR.ARPA." );
irrp = make_rr(RR_INQUERY,NULLCHAR,CLASS_IN,TYPE_A,0,4,&ip_address);
prrp = make_rr(RR_QUERY,pname,CLASS_IN,TYPE_PTR,0,0,NULL);
irrp->next = prrp; /* make list to speed search */
for(dname = NULLCHAR; dname == NULLCHAR;){
if((rrp=dcache_search(irrp)) == NULLRR
&& (rrp=dfile_search(irrp)) == NULLRR
&& (rrp=dns_query(prrp,1)) == NULLRR)
break;
if(rrp->rdlength == 0)
break;
switch(rrp->type){
case TYPE_A:
dname = strxdup(rrp->name);
break;
case TYPE_PTR:
dname = strxdup(rrp->rdata.name);
break;
default:
free_rr(rrp);
}
}
free_rr(irrp);
free_rr(prrp);
free_rr(rrp);
return dname;
#endif
}
/* Main entry point for M* record lookup.
* Returns NULLCHAR if name is currently unresolvable.
*/
char *
resolve_mailb(char *name)
{
struct rr *rrp, *arrp;
char *sname, *tmp, *cp;
int32 addr = 0;
int16 pref = MAXINT16;
if(name == NULLCHAR) {
return NULLCHAR;
}
if(isaddr(name)) {
if((sname = resolve_a(aton(name),FALSE)) == NULLCHAR) {
return NULLCHAR;
}
} else {
sname = mxallocw(strxlen(name) + 2);
sprintf(sname,"%s.",name);
}
cp = sname;
while(1){
rrp = arrp = rresolve(sname,TYPE_MX,DOM_CANRECURSE);
/* Search this list of rr's for an MX record */
while(rrp != NULLRR) {
if(rrp->rdlength > 0 && rrp->rdata.mx.pref <= pref
&& (addr = resolve(rrp->rdata.mx.exch)) != 0L) {
pref = rrp->rdata.mx.pref;
}
rrp = rrp->next;
}
free_rr(arrp);
if(addr != 0) {
break;
}
/* Compose wild card one level up */
if((cp = strchr(cp,'.')) == NULLCHAR) {
break;
}
tmp = mxallocw(strxlen(cp)+2);
sprintf(tmp,"*%s",cp); /* wildcard expansion */
xfree(sname);
sname = tmp;
cp = sname + 2;
}
if(Dsuffix != NULLCHAR && addr != 0) {
if(!strstr(sname,Dsuffix)) {
char cp1[2];
tmp = mxallocw(strxlen(sname) + strxlen(Dsuffix) + 2);
if(sname[strxlen(sname) - 1] != '.') {
strcpy(cp1,".");
} else {
strcpy(cp1,"");
}
sprintf(tmp,"%s%s%s",sname,cp1,Dsuffix);
xfree(sname);
return tmp;
} else {
return sname;
}
}
xfree(sname);
return NULLCHAR;
}
#ifdef XXX
/* process outgoing zoneinit */
static void
proc_bootp(int s,void *d,void *b)
{
int count, len, answers = 5;
char *buf;
struct sockaddr_in server;
struct rr *rrp;
struct quest *qp;
struct rr_memory *memory;
FILE *fp;
struct mbuf *bp;
struct Server *dp = (struct Server *) d;
struct dhdr *dhdr = (struct dhdr *) b;
if(dhdr->qdcount != 1) {
free_dhdr(dhdr);
xfree(dp);
return;
}
qp = dhdr->qlist[0]; /* expecting only 1 question */
if(qp->qtype == TYPE_ANY) {
int auth = DOM_AUTHORITY | DOM_CANRECURSE;
char *name = strxdup(qp->qname);
int i = strxlen(name);
if(name[--i] == '.') {
name[i] = '\0'; /* undo effect of dn_compress */
}
dhdr->rcode = NO_ERROR;
dhdr->aa = auth;
dhdr->qr = RESPONSE;
dhdr->opcode = QUERY; /* change opcode for answers */
if((fp = Fopen(name,READ_TEXT,0,0)) == NULLFILE) {
xfree(name);
free_dhdr(dhdr);
xfree(dp);
return;
}
memory = mxallocw(sizeof(struct rr_memory));
dhdr->ans = cxallocw(answers,sizeof(struct rr *));
server.sin_family = AF_INET;
server.sin_port = dp->protocol;
server.sin_addr.s_addr = dp->address;
count = 0;
buf = mxallocw(512);
while((rrp = get_rr(fp,memory)) != NULLRR) {
dhdr->ans[count++] = rrp;
if(count == answers) {
dhdr->ancount = answers;
len = res_mkbuf(dhdr,buf,512);
bp = qdata(buf,(int16)len);
send_mbuf(s,bp,0,(char *)&server,SOCKSIZE);
for(i = 0; i < answers; i++) {
free_rr(dhdr->ans[i]);
dhdr->ans[i] = NULLRR;
}
count = 0;
alarm(Dtimeout * 1000);
/* Wait for something to happen */
pwait(&s);
alarm(0L);
}
}
dhdr->ancount = count;
len = res_mkbuf(dhdr,buf,512);
free_dhdr(dhdr);
bp = qdata(buf,(int16)len);
send_mbuf(s,bp,0,(char *)&server,SOCKSIZE);
xfree(buf);
xfree(dp);
xfree(name);
Fclose(fp);
}
}
#endif
#ifdef DNS
/* process incoming queries */
void
proc_query(int s,void *d,void *b)
{
int i, len;
char *buf;
struct sockaddr_in server;
struct rr *rrp, *rrans, *rrns, *rradd, *rrtmp;
struct mbuf *bp;
struct Server *dp = (struct Server *) d;
struct dhdr *dhdr = (struct dhdr *) b;
rrans = rrns = rradd = NULLRR;
for(i = 0; i < dhdr->qdcount; i++) {
struct quest *qp = dhdr->qlist[i];
/* A server is testing here. ASSUMING INTERNET STYLE */
int auth = (Dhaveaa) ? (DOM_AUTHORITY | DOM_CANRECURSE) : DOM_CANRECURSE;
#ifdef XXX
int auth = (haveaa(qp->qname)) ? (DOM_AUTHORITY | DOM_CANRECURSE) : DOM_CANRECURSE;
#endif
dhdr->aa = auth;
dhdr->qr = RESPONSE;
switch(qp->qtype) {
case TYPE_A:
if((rrp = rresolve(qp->qname,TYPE_A,DOM_CANRECURSE)) != NULLRR) {
/* we found an entry, go tell him */
dhdr->rcode = NO_ERROR;
} else {
/* we did not find an entry, go tell him */
rrp = mxallocw(sizeof(struct rr));
rrp->name = strxdup(qp->qname);
rrp->type = qp->qtype;
rrp->class = qp->qclass;
rrp->ttl = 500L;
rrp->rdata.addr = 0L;
rrp->rdlength = 4; /* size of addr data */
dhdr->rcode = NAME_ERROR;
}
rrans = rrp;
break;
case TYPE_MB:
case TYPE_MG:
case TYPE_MR:
case TYPE_MX:
case TYPE_NS:
case TYPE_SOA:
case TYPE_PTR:
case TYPE_TXT:
case TYPE_CNAME:
case TYPE_HINFO:
case TYPE_ANY:
if((rrp = rresolve(qp->qname,qp->qtype,DOM_CANRECURSE)) != NULLRR) {
dhdr->rcode = NO_ERROR;
} else {
dhdr->rcode = NAME_ERROR;
}
rrans = rrp;
break;
/* if I cannot give a reasonable answer , dont give it ... */
case TYPE_MD: /* unsupported */
case TYPE_MF: /* unsupported */
case TYPE_WKS: /* unsupported */
case TYPE_NULL: /* unsupported */
case TYPE_MINFO: /* unsupported */
default:
dhdr->rcode = NOT_IMPL;
}
}
i = 0;
rrtmp = rrans;
while(rrtmp != NULLRR) {
i++;
rrtmp = rrtmp->next;
}
if((dhdr->ancount = i) > 0) {
dhdr->ans = cxallocw(i,sizeof(struct rr *));
rrtmp = rrans;
i = 0;
while(rrtmp != NULLRR) {
dhdr->ans[i] = rrtmp;
i++;
rrans = rrtmp;
rrtmp = rrtmp->next;
rrans->next = NULLRR; /* break link */
}
}
i = 0;
rrtmp = rrns;
while(rrtmp != NULLRR) {
i++;
rrtmp = rrtmp->next;
}
if((dhdr->nscount = i) > 0) {
dhdr->ns = cxallocw(i,sizeof(struct rr *));
rrtmp = rrns;
i = 0;
while(rrtmp != NULLRR) {
dhdr->ns[i] = rrtmp;
i++;
rrns = rrtmp;
rrtmp = rrtmp->next;
rrns->next = NULLRR; /* break link */
}
}
i = 0;
rrtmp = rradd;
while(rrtmp != NULLRR) {
i++;
rrtmp = rrtmp->next;
}
if((dhdr->arcount = i) > 0) {
dhdr->add = cxallocw(i,sizeof(struct rr *));
rrtmp = rradd;
i = 0;
while(rrtmp != NULLRR) {
dhdr->add[i] = rrtmp;
i++;
rradd = rrtmp;
rrtmp = rrtmp->next;
rradd->next = NULLRR; /* break link */
}
}
buf = mxallocw(512);
len = res_mkbuf(dhdr,buf,512);
free_dhdr(dhdr);
server.sin_family = AF_INET;
server.sin_port = dp->protocol;
server.sin_addr.s_addr = dp->address;
bp = qdata(buf,(int16)len);
send_mbuf(s,bp,0,(char *)&server,SOCKSIZE);
xfree(buf);
xfree(dp);
}
#endif